package com.wlps.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wlps.contant.Contant;
import com.wlps.entity.*;
import com.wlps.mapper.CommodityMapper;
import com.wlps.mapper.FirstClassificationMapper;
import com.wlps.mapper.SecondClassificationMapper;
import com.wlps.mapper.SupplierMapper;
import com.wlps.result.ResultPageVo;
import com.wlps.result.ResultUtils;
import com.wlps.result.ResultVo;
import com.wlps.service.ICommodityService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wlps.vo.sendcenter.commodity.CommodityAddVo;
import com.wlps.vo.sendcenter.commodity.CommodityConditionVo;
import com.wlps.vo.sendcenter.commodity.CommodityUpdateVo;
import com.wlps.vo.sendcenter.inoutform.CommodityAndWarehouseVo;
import com.wlps.vo.sendcenter.inoutform.CommodityInOutConditionVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 商品表（commodity）
 * (1当有正在执行的订单时，不能删除商品。)
 * (如果是订购系统-订单的话不建议更新数据库建议更新redis到0的时候在更新数据库，也可以定时更新感觉可以使用这样的索引覆盖决定不习可以去掉) 服务实现类
 * </p>
 *
 * @author ZWYZY
 * @since 2020-07-31
 */
@Service
@Slf4j
public class CommodityServiceImpl extends ServiceImpl<CommodityMapper, Commodity> implements ICommodityService, InitializingBean {
    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    FirstClassificationMapper firstClassificationMapper;

    @Autowired
    SecondClassificationMapper secondClassificationMapper;

    @Autowired
    SupplierMapper supplierMapper;

    @Override
    public void afterPropertiesSet() throws Exception {
        initOutCommodityAndWarehouseVo();
        initInCommodityAndWarehouseVo();
        initCommodity();
    }

    /**
     * 初始化缓存
     */
    void initOutCommodityAndWarehouseVo() {
        List<CommodityAndWarehouseVo> commodityAndWarehouseVos;
        if (redisTemplate.hasKey(Contant.COMMODITYANDWAREHOUSEVOSOUT_KEY)) {
            commodityAndWarehouseVos = (List<CommodityAndWarehouseVo>) redisTemplate.opsForValue().get(Contant.COMMODITYANDWAREHOUSEVOSOUT_KEY);

        } else {
            commodityAndWarehouseVos = baseMapper.selectCommodityByCommodityAndWarehouseOutVo();
            redisTemplate.opsForValue().set(Contant.COMMODITYANDWAREHOUSEVOSOUT_KEY, commodityAndWarehouseVos,5,TimeUnit.MINUTES);

            log.info("初始化所有需出库商品------存入缓存数据");
        }
        if (!redisTemplate.hasKey(Contant.COMMODITYANDWAREHOUSEVOOUTLIST_KEY)) {
            redisTemplate.opsForList().rightPushAll(Contant.COMMODITYANDWAREHOUSEVOOUTLIST_KEY, commodityAndWarehouseVos);
            redisTemplate.expire(Contant.COMMODITYANDWAREHOUSEVOOUTLIST_KEY,5,TimeUnit.MINUTES);
            log.info("初始化所有需出库商品列表--------存入缓存数据");
        }

    }

    /**
     * 初始化缓存
     */
    void initCommodity() {
        List<Commodity> commodities;
        if (redisTemplate.hasKey(Contant.COMMODITYS_KEY)) {
            commodities = (List<Commodity>) redisTemplate.opsForValue().get(Contant.COMMODITYS_KEY);
        } else {
            commodities = baseMapper.selectList(null);
            redisTemplate.opsForValue().set(Contant.COMMODITYS_KEY, commodities,5, TimeUnit.MINUTES);
            log.info("初始化所有商品------存入缓存数据");
        }
        if (!redisTemplate.hasKey(Contant.COMMODITYLIST_KEY)) {
            redisTemplate.opsForList().rightPushAll(Contant.COMMODITYLIST_KEY,commodities);
            redisTemplate.expire(Contant.COMMODITYLIST_KEY,5,TimeUnit.MINUTES);
            log.info("初始化商品列表--------存入缓存数据");
        }

    }

    /**
     * 初始化缓存
     */
    void initInCommodityAndWarehouseVo() {
        List<CommodityAndWarehouseVo> commodityAndWarehouseVos;
        if (redisTemplate.hasKey(Contant.COMMODITYANDWAREHOUSEVOSIN_KEY)) {
            commodityAndWarehouseVos = (List<CommodityAndWarehouseVo>) redisTemplate.opsForValue().get(Contant.COMMODITYANDWAREHOUSEVOSIN_KEY);
        } else {
            commodityAndWarehouseVos = baseMapper.selectCommodityByCommodityAndWarehouseInVo();
            redisTemplate.opsForValue().set(Contant.COMMODITYANDWAREHOUSEVOSIN_KEY, commodityAndWarehouseVos,5,TimeUnit.MINUTES);
            log.info("初始化所有需入库商品------存入缓存数据");
        }
        if (!redisTemplate.hasKey(Contant.COMMODITYANDWAREHOUSEVOINLIST_KEY)) {
            redisTemplate.opsForList().rightPushAll(Contant.COMMODITYANDWAREHOUSEVOINLIST_KEY, commodityAndWarehouseVos);
            redisTemplate.expire(Contant.COMMODITYANDWAREHOUSEVOINLIST_KEY,5,TimeUnit.MINUTES);
            log.info("初始化所有需入库商品列表--------存入缓存数据");
        }

    }
    @Override
    public ResultPageVo<List<CommodityAndWarehouseVo>> getCommodityAndWarehouseOutVo(int pageNum, int pageSize, CommodityInOutConditionVo commodityInOutConditionVo) {
        initOutCommodityAndWarehouseVo();

        //总条数
        int count;
        //偏移量
        int fromNum;
        //终止量
        int toNum;
        List<CommodityAndWarehouseVo> commodityAndWarehouseVoList = (List<CommodityAndWarehouseVo>) redisTemplate.opsForValue().get(Contant.COMMODITYANDWAREHOUSEVOSOUT_KEY);
        if (commodityInOutConditionVo == null) {
            //不是条件查询，redis
            count = commodityAndWarehouseVoList.size();

        } else {
            Stream<CommodityAndWarehouseVo> stream = commodityAndWarehouseVoList.stream();
            if (commodityInOutConditionVo.getCommodityName() != null) {
                String name = commodityInOutConditionVo.getCommodityName();
                stream=stream.filter(x -> x != null && name.equals(x.getProductName()));

            }
            if (commodityInOutConditionVo.getStartTime() != null) {
                Date date = commodityInOutConditionVo.getStartTime();
                stream=stream.filter(x -> x != null && x.getUpdateTime().after(date));
            }
            if (commodityInOutConditionVo.getEndTime() != null) {
                Date date = commodityInOutConditionVo.getEndTime();
               stream= stream.filter(x -> x != null && x.getUpdateTime().before(date));
            }
            if (commodityInOutConditionVo.getSupplierName() != null) {
                String suppliyName = commodityInOutConditionVo.getSupplierName();
                stream=stream.filter(x -> x != null && suppliyName.equals(x.getSupplier()));
            }
            commodityAndWarehouseVoList = stream.collect(Collectors.toList());
            count = commodityAndWarehouseVoList.size();
        }
        //当前页从第几条开始查
        fromNum = pageSize * (pageNum - 1);
        if(fromNum>=count)
        {
//            sysUserList=null;
        }else{
            //当前页最后第几条
            toNum = fromNum + pageSize >= count ? count : fromNum + pageSize;
            commodityAndWarehouseVoList = commodityAndWarehouseVoList.subList(fromNum, toNum);
        }
        //当前页最后第几条

        //分页返回值封装
        ResultPageVo resultPageVo = new ResultPageVo("响应成功", 200, (long) pageSize, (long) pageNum, (long) count, commodityAndWarehouseVoList);
        return resultPageVo;
    }

    @Override
    public ResultPageVo<List<CommodityAndWarehouseVo>> getCommodityAndWarehouseInVo(int pageNum, int pageSize, CommodityInOutConditionVo commodityInOutConditionVo) {
        initInCommodityAndWarehouseVo();

        //总条数
        int count;
        //偏移量
        int fromNum;
        //终止量
        int toNum;
        List<CommodityAndWarehouseVo> commodityAndWarehouseVoList = (List<CommodityAndWarehouseVo>) redisTemplate.opsForValue().get(Contant.COMMODITYANDWAREHOUSEVOSIN_KEY);
        if (commodityInOutConditionVo == null) {
            //不是条件查询，redis
            count = commodityAndWarehouseVoList.size();

        } else {
            Stream<CommodityAndWarehouseVo> stream = commodityAndWarehouseVoList.stream();
            if (commodityInOutConditionVo.getCommodityName() != null) {
                String name = commodityInOutConditionVo.getCommodityName();
                stream=stream.filter(x -> x != null && name.equals(x.getProductName()));

            }
            if (commodityInOutConditionVo.getStartTime() != null) {
                Date date = commodityInOutConditionVo.getStartTime();
                stream=stream.filter(x -> x != null && x.getUpdateTime().after(date));
            }
            if (commodityInOutConditionVo.getEndTime() != null) {
                Date date = commodityInOutConditionVo.getEndTime();
                stream= stream.filter(x -> x != null && x.getUpdateTime().before(date));
            }
            if (commodityInOutConditionVo.getSupplierName() != null) {
                String suppliyName = commodityInOutConditionVo.getSupplierName();
                stream=stream.filter(x -> x != null && suppliyName.equals(x.getSupplier()));
            }
            commodityAndWarehouseVoList = stream.collect(Collectors.toList());
            count = commodityAndWarehouseVoList.size();
        }
        //当前页从第几条开始查
        fromNum = pageSize * (pageNum - 1);
        if(fromNum>=count)
        {
//            sysUserList=null;
        }else{
            //当前页最后第几条
            toNum = fromNum + pageSize >= count ? count : fromNum + pageSize;
            commodityAndWarehouseVoList = commodityAndWarehouseVoList.subList(fromNum, toNum);
        }
        //当前页最后第几条

        //分页返回值封装
        ResultPageVo resultPageVo = new ResultPageVo("响应成功", 200, (long) pageSize, (long) pageNum, (long) count, commodityAndWarehouseVoList);
        return resultPageVo;
    }

    @Override
    public ResultPageVo<List<Commodity>> getCommodity(int pageNum, int pageSize, CommodityConditionVo commodityConditionVo) {
        initCommodity();
        //总条数
        int count;
        //偏移量
        int fromNum;
        //终止量
        int toNum;
        List<Commodity> commodities = (List<Commodity>) redisTemplate.opsForValue().get(Contant.COMMODITYS_KEY);
        if (commodityConditionVo == null) {
            //不是条件查询，redis
            count = commodities.size();

        } else {
            Stream<Commodity> stream = commodities.stream();
            if (commodityConditionVo.getSecondName() == null && commodityConditionVo.getFirstName() != null) {
                String firstName = commodityConditionVo.getFirstName();
                stream=stream.filter(x -> x != null && firstName.equals(x.getFirstClassification()));
            } else if (StringUtils.isNotBlank(commodityConditionVo.getSecondName()) && StringUtils.isNotBlank(commodityConditionVo.getFirstName())) {
                String firstName = commodityConditionVo.getFirstName();
                String secondName = commodityConditionVo.getSecondName();
                stream=stream.filter(x -> x != null && firstName.equals(x.getFirstClassification()) && secondName.equals(x.getSecondClassification()));
            }
            if (commodityConditionVo.getStartTime() != null) {
                Date date = commodityConditionVo.getStartTime();
                stream=stream.filter(x -> x != null && x.getUpdateTime().after(date));
            }
            if (commodityConditionVo.getEndTime() != null) {
                Date date = commodityConditionVo.getEndTime();
                stream=stream.filter(x -> x != null && x.getUpdateTime().before(date));
            }

            commodities = stream.collect(Collectors.toList());
            count = commodities.size();
        }
        //当前页从第几条开始查
        fromNum = pageSize * (pageNum - 1);
        if(fromNum>=count)
        {
//            sysUserList=null;
        }else{
            //当前页最后第几条
            toNum = fromNum + pageSize >= count ? count : fromNum + pageSize;
            commodities = commodities.subList(fromNum, toNum);
        }
        //当前页最后第几条

        //分页返回值封装
        ResultPageVo resultPageVo = new ResultPageVo("响应成功", 200, (long) pageSize, (long) pageNum, (long) count, commodities);
        return resultPageVo;
    }

    @Override
    public ResultVo addCommodity(CommodityAddVo commodityAddVo) {
        if (firstClassificationMapper.selectList(new QueryWrapper<FirstClassification>().lambda().eq(FirstClassification::getFirstName, commodityAddVo.getFirstClassification())) .size() ==0) {
            return ResultUtils.error("系统没有该一级分类名称，请输入系统已录入的一级分类名称试试，亲", 80000);
        }

        if (secondClassificationMapper.selectList(new QueryWrapper<SecondClassification>().lambda().eq(SecondClassification::getSecondName, commodityAddVo.getSecondClassification())) .size()==0) {
            return ResultUtils.error("系统没有该二级分类名称，请输入系统已录入的二级分类名称试试，亲", 80001);
        }
        if (((List<Commodity>) redisTemplate.opsForValue().get(Contant.COMMODITYS_KEY)).stream().filter(x -> x != null && commodityAddVo.getProductName().equals(x.getProductName())).count() != 0) {
            return ResultUtils.error("系统有同名商品，请换个商品名称试试，亲", 80002);
        }
        if (((List<Supplier>) redisTemplate.opsForValue().get(Contant.SUPPLIERS_KEY)).stream().filter(x -> x != null && commodityAddVo.getSupplier().equals(x.getSupplierName())).count() == 0) {
            return ResultUtils.error("系统没有录入该供应商名称，请输入系统已录入的供应商名称试试，亲", 80003);
        }
        Commodity commodity = new Commodity();
        BeanUtils.copyProperties(commodityAddVo, commodity);
        baseMapper.insert(commodity);
        commodityUpdateCache();
        return ResultUtils.success("创建商品成功");
    }

    @Override
    public ResultVo deleteCommodity(Long id) {
        List<Commodity> list=(List<Commodity>)redisTemplate.opsForValue().get(Contant.COMMODITYS_KEY);
        long count=list.stream().filter(x -> x != null && id.equals(x.getId())).count();
        if (count==0) {
            return ResultUtils.error("商品id查询不到，请输入正确的商品id，亲", 80004);
        }
        if(baseMapper.selectCommodityOrder(id).size()!=0)
        {
            return ResultUtils.error("系统检查出本商品已有订单记录，不能删除，亲",80005);
        }
        baseMapper.deleteById(id);
        commodityUpdateCache();
        return ResultUtils.success("操作成功");
    }

    @Override
    public ResultVo updateCommodity(CommodityUpdateVo commodityUpdateVo) {
        if (firstClassificationMapper.selectList(new QueryWrapper<FirstClassification>().lambda().eq(FirstClassification::getFirstName, commodityUpdateVo.getFirstClassification())) .size()==0) {
            return ResultUtils.error("系统没有该一级分类名称，请输入系统已录入的一级分类名称试试，亲", 80000);
        }

        if (secondClassificationMapper.selectList(new QueryWrapper<SecondClassification>().lambda().eq(SecondClassification::getSecondName, commodityUpdateVo.getSecondClassification())).size()==0) {
            return ResultUtils.error("系统没有该二级分类名称，请输入系统已录入的二级分类名称试试，亲", 80001);
        }
        if (((List<Commodity>) redisTemplate.opsForValue().get(Contant.COMMODITYS_KEY)).stream().filter(x -> x != null && commodityUpdateVo.getProductName().equals(x.getProductName()) && !commodityUpdateVo.getId().equals(x.getId())).count() != 0) {
            return ResultUtils.error("系统有同名商品，请换个商品名称试试，亲", 80002);
        }
        if (((List<Supplier>) redisTemplate.opsForValue().get(Contant.SUPPLIERS_KEY)).stream().filter(x -> x != null && commodityUpdateVo.getSupplier().equals(x.getSupplierName())).count() == 0) {
            return ResultUtils.error("系统没有录入该供应商名称，请输入系统已录入的供应商名称试试，亲", 80003);
        }
        Commodity commodity=new Commodity();
        BeanUtils.copyProperties(commodityUpdateVo,commodity);
        baseMapper.updateById(commodity);
        commodityUpdateCache();
        return ResultUtils.success("更改商品成功");
    }

    /**
     * 更新缓存
     */
    @Async
    public void commodityUpdateCache() {
        List<Commodity> commodityList = baseMapper.selectList(null);
        redisTemplate.opsForValue().set(Contant.COMMODITYS_KEY, commodityList,5,TimeUnit.MINUTES);
        redisTemplate.delete(Contant.COMMODITYLIST_KEY);
        redisTemplate.opsForList().rightPushAll(Contant.COMMODITYLIST_KEY, commodityList);
        redisTemplate.expire(Contant.COMMODITYLIST_KEY,5,TimeUnit.MINUTES);
        log.info("所有商品-------更新缓存数据");
    }
}
